Skip to content

Add Spec Kit assess canvas dashboard - #4

Merged
mnriem merged 31 commits into
github:mainfrom
mnriem:mnriem-install-assess-canvas
Aug 3, 2026
Merged

Add Spec Kit assess canvas dashboard#4
mnriem merged 31 commits into
github:mainfrom
mnriem:mnriem-install-assess-canvas

Conversation

@mnriem

@mnriem mnriem commented Jul 31, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • establish this repository as the GitHub Copilot integration hub for Spec Kit
  • add spec-kit-copilot-assess, an independently installable Copilot App canvas plugin for the Spec Kit assessment funnel
  • integrate skills-mode stage runs/reruns, artifact previews, stale-state tracking, and targeted clarifications
  • harden filesystem reads and loopback APIs, including symlink, size, race, capability, and prerequisite checks

Distribution

The marketplace now exposes two independently versioned plugins:

  • spec-kit-copilot v0.15.0 — the existing core Spec Kit skills
  • spec-kit-copilot-assess v0.1.0 — the optional Idea Assessment canvas

The canvas plugin lives under plugins/spec-kit-copilot-assess/ and declares its own extensions/ component path. Installing the core skills plugin does not install or enable the canvas.

Validation

Both plugins were installed independently from the repository's marketplace in an isolated COPILOT_HOME; the core installed nine skills and the assessment plugin installed its canvas extension. The canvas implementation was also exercised through the GitHub Copilot App runtime before the packaging split.

mnriem and others added 24 commits July 2, 2026 09:03
Add the standard community-health files required by the open-source
release checklist (github/open-source-releases#706), aligned with the
sibling github/spec-kit repository:

- LICENSE (MIT, Copyright GitHub, Inc.)
- CODE_OF_CONDUCT.md (Contributor Covenant 1.4)
- SECURITY.md
- SUPPORT.md
- CONTRIBUTING.md (tailored to this skills plugin)
- .github/CODEOWNERS (@mnriem)
- README.md: add Background, License, Maintainers, Support, and
  Acknowledgement sections

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Assisted-by: GitHub Copilot (model: Claude Opus 4.8, autonomous)

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
Copilot AI review requested due to automatic review settings July 31, 2026 19:54

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Not ready to approve

Command dispatch, symlink safety, stale-state handling, and contributor guidance have unresolved correctness issues.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.

Pull request overview

Adds a Copilot canvas dashboard for the Spec Kit assessment pipeline, alongside generated project setup, assessment fixtures, and community documentation.

Changes:

  • Adds assessment scanning, previews, stage execution, reruns, clarifications, and live updates.
  • Installs the assess pipeline and generated Copilot skills.
  • Adds repository governance and support documentation.
File summaries
File Description
SUPPORT.md Adds support guidance.
SECURITY.md Adds vulnerability reporting policy.
README.md Expands project background and policies.
LICENSE Adds MIT license.
CONTRIBUTING.md Adds contribution workflow.
CODE_OF_CONDUCT.md Adds contributor conduct policy.
.specify/workflows/workflow-registry.json Registers the SDD workflow.
.specify/workflows/speckit/workflow.yml Defines the full SDD cycle.
.specify/templates/tasks-template.md Adds the task-generation template.
.specify/templates/spec-template.md Adds the feature-specification template.
.specify/templates/plan-template.md Adds the implementation-plan template.
.specify/templates/constitution-template.md Adds the constitution template.
.specify/templates/checklist-template.md Adds the checklist template.
.specify/scripts/bash/setup-tasks.sh Prepares task-generation inputs.
.specify/scripts/bash/setup-plan.sh Prepares planning inputs.
.specify/scripts/bash/check-prerequisites.sh Validates workflow prerequisites.
.specify/memory/constitution.md Adds the initial constitution placeholder.
.specify/memory/.constitution-template.json Records the constitution template hash.
.specify/integrations/speckit.manifest.json Records installed Spec Kit files.
.specify/integrations/copilot.manifest.json Records generated Copilot skills.
.specify/integration.json Configures Copilot skills mode.
.specify/init-options.json Records initialization options.
.specify/extensions/assess/README.md Documents the assess pipeline.
.specify/extensions/assess/extension.yml Declares assess commands.
.specify/extensions/assess/commands/speckit.assess.shape.md Defines concept shaping.
.specify/extensions/assess/commands/speckit.assess.research.md Defines evidence research.
.specify/extensions/assess/commands/speckit.assess.intake.md Defines idea intake.
.specify/extensions/assess/commands/speckit.assess.define.md Defines problem framing.
.specify/extensions/assess/commands/speckit.assess.decide.md Defines assessment decisions.
.specify/extensions/.registry Registers the assess extension.
.specify/extensions/.cache/catalog.json Caches the extension catalog.
.specify/extensions/.cache/catalog-metadata.json Records catalog cache metadata.
.specify/extensions/.cache/catalog-ebf165086500aab1-metadata.json Records community catalog metadata.
.specify/extensions.yml Enables assess extension settings.
.specify/assessments/spec-kit-sdd-canvas/research.md Captures canvas research.
.specify/assessments/spec-kit-sdd-canvas/problem.md Defines the canvas problem.
.specify/assessments/spec-kit-sdd-canvas/intake.md Captures the original idea.
.specify/assessments/spec-kit-sdd-canvas/decision.md Records the assessment verdict.
.specify/assessments/spec-kit-sdd-canvas/concept.md Compares canvas concepts.
.github/skills/speckit-taskstoissues/SKILL.md Adds task-to-issue guidance.
.github/skills/speckit-tasks/SKILL.md Adds task-generation guidance.
.github/skills/speckit-plan/SKILL.md Adds planning guidance.
.github/skills/speckit-implement/SKILL.md Adds implementation guidance.
.github/skills/speckit-converge/SKILL.md Adds convergence analysis.
.github/skills/speckit-constitution/SKILL.md Adds constitution guidance.
.github/skills/speckit-clarify/SKILL.md Adds clarification guidance.
.github/skills/speckit-assess-shape/SKILL.md Exposes assessment shaping.
.github/skills/speckit-assess-research/SKILL.md Exposes assessment research.
.github/skills/speckit-assess-intake/SKILL.md Exposes assessment intake.
.github/skills/speckit-assess-define/SKILL.md Exposes problem definition.
.github/skills/speckit-assess-decide/SKILL.md Exposes assessment decisions.
.github/skills/speckit-analyze/SKILL.md Adds artifact consistency analysis.
.github/extensions/assess-canvas/README.md Documents the canvas dashboard.
.github/extensions/assess-canvas/extension.mjs Implements canvas actions and HTTP/SSE.
.github/extensions/assess-canvas/copilot-extension.json Declares the canvas extension.
.github/extensions/assess-canvas/assess.js Scans and reads assessment artifacts.
.github/CODEOWNERS Assigns the repository owner.
Review details

Suppressed comments (5)

.github/extensions/assess-canvas/assess.js:208

  • This containment check is lexical, but statSync/readFileSync follow symlinks. A crafted checkout can make an allowed artifact such as intake.md a symlink to an arbitrary same-user file, which /api/artifact will then expose. Reject symlinks in .specify, assessments, the slug directory, and the artifact with lstat, then verify the real path remains under the real assessments directory before reading.
    const assessDir = resolve(join(projectRoot, ".specify", "assessments"));
    const filePath = resolve(join(assessDir, cleanSlug, stage.file));
    const expected = join(assessDir, cleanSlug, stage.file);
    if (filePath !== expected) return { ok: false, error: "path escape" };
    if (!filePath.startsWith(assessDir + "/")) return { ok: false, error: "path escape" };
    if (!existsSync(filePath)) return { ok: false, error: "not found" };
    const content = readIfFile(filePath);
    if (content === null) return { ok: false, error: "not a file" };

.github/extensions/assess-canvas/assess.js:147

  • The contiguous-chain rule marks every later artifact stale whenever an earlier optional stage is absent. The assess contract explicitly permits research without intake and makes define the minimum viable stage, so a valid define-only assessment is shown as stale/zero progress and directed back to intake. Compute freshness from each stage's actual required prerequisites and newer existing inputs instead of requiring every preceding artifact.
            const stale = exists && (!chainCurrent || (latestMtime > 0 && mtime < latestMtime));
            const done = exists && !stale;

.github/extensions/assess-canvas/assess.js:250

  • The SSE signature omits prerequisite state. Installing Spec Kit/assess usually leaves the assessments directory absent, so the signature stays 0 and no update is broadcast; the open canvas remains stuck on “Setup required” until reloaded. Include initialized and assessInstalled (or setupRequired) in the signature.
export function stateSignature(state) {
    const parts = [state.exists ? "1" : "0"];

.github/extensions/assess-canvas/assess.js:205

  • This hard-coded / makes all valid artifact paths fail the containment check on Windows, where path.resolve uses backslashes. The preceding equality check already verifies the normalized slug plus fixed stage filename; remove the platform-specific prefix check (or use path.relative).
    if (filePath !== expected) return { ok: false, error: "path escape" };
    if (!filePath.startsWith(assessDir + "/")) return { ok: false, error: "path escape" };

CONTRIBUTING.md:50

  • The plugin version is intentionally independent from the installed specify CLI version; initialization records whichever current CLI is used. Requiring lockstep versions and a targeted CLI release would incorrectly pin contributors and undo that compatibility model.
  • Files reviewed: 62/63 changed files
  • Comments generated: 4
  • Review effort level: Balanced

We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.

Comment thread .github/extensions/assess-canvas/assess.js Outdated
Comment thread .github/extensions/assess-canvas/extension.mjs Outdated
Comment thread CONTRIBUTING.md
Comment thread .specify/workflows/speckit/workflow.yml Outdated
mnriem added 2 commits August 3, 2026 08:48
Use generated skill invocations, enforce current stage prerequisites, reject symlinked artifacts, and track prerequisite changes in live updates. Remove generated Spec Kit setup and assessment fixtures from the PR.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
Copilot AI review requested due to automatic review settings August 3, 2026 13:50

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Not ready to approve

Stale-state propagation, prerequisite enforcement, loopback API security, and accessibility issues remain unresolved.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.

Review details

Suppressed comments (10)

.github/extensions/assess-canvas/index.html:158

  • The stage-guidance textarea has no associated label, so assistive technology cannot reliably identify the field after its placeholder disappears. Give it an explicit accessible name.
  <textarea id="stageInstructions" placeholder="Optional guidance for this stage"></textarea>

.github/extensions/assess-canvas/index.html:169

  • The required clarification-answer textarea has no associated label; relying only on placeholder text leaves the control without a persistent accessible name. Add an explicit accessible name.
  <textarea id="clarifyAnswer" placeholder="Required clarification answer"></textarea>

.github/extensions/assess-canvas/index.html:142

  • These two inputs have no associated label; placeholder text is not a persistent accessible name and disappears as soon as users type. Add visible <label> elements, or at minimum explicit accessible names, for the idea and slug fields.

This issue also appears in the following locations of the same file:

  • line 158
  • line 169
      <textarea id="idea" placeholder="Let users work offline and sync when they reconnect"></textarea>
      <div class="row" style="margin-top: 8px;">
        <input type="text" id="newslug" placeholder="slug (optional, e.g. offline-mode)" style="max-width: 60%;" />

.github/extensions/assess-canvas/assess.js:162

  • Staleness is not propagated transitively. After rerunning intake, research becomes stale; if define is then rerun without refreshing research, its newer mtime makes it done even though the define skill reads the still-stale research.md. Downstream stages can consequently be reported current while depending on stale content. Treat an existing stale prior stage as stale input in addition to comparing mtimes.
            const newerInput = STAGES.slice(0, index).some((input) => {
                const inputState = stages[input.key];
                return inputState.exists && inputState.mtime > state.mtime;
            });

.github/extensions/assess-canvas/index.html:281

  • This uses mere existence rather than currentness, so Shape and Decide are presented as available when problem.md is stale. The server then rejects the action, contradicting the dashboard's enabled state. Match the server guard by requiring define.done.
  if (stage === "shape" || stage === "decide") return Boolean(assessment.stages.define.exists);

.github/extensions/assess-canvas/index.html:252

  • Existing artifacts bypass the computed available flag entirely. Thus an existing Shape or Decide pill remains clickable even when its current-stage prerequisite is unavailable; it opens a rerun dialog that can only fail at the server. Apply availability to reruns too.
    if (st.exists) {
      p.title = "Run " + s.command + " again";
      p.onclick = () => openStageDialog(s.key, a.slug, true, a.title);

.github/extensions/assess-canvas/extension.mjs:118

  • Clarification reruns bypass the setup prerequisite enforced by /api/run and run_stage. If the assess extension was removed while artifacts remain, this path still sends an unavailable /skill:speckit-assess-* prompt instead of directing the user through setup. Reject clarification runs while setup is required.
    const artifact = readArtifact(PROJECT_ROOT, slug, stage.key);
    if (!artifact.ok) return { error: artifact.error };

.github/extensions/assess-canvas/extension.mjs:130

  • This direct dispatch also bypasses buildPrompt's current-problem guard. A clarification opened from a stale concept.md, or a decision whose revisit stage is Shape, can therefore rerun Shape while Define is stale and use an outdated problem. Validate the resolved target's prerequisite before sending.
    const prompt = [

.github/extensions/assess-canvas/index.html:392

  • The form is cleared immediately, before the request has succeeded. Any network failure or server rejection (for example, a slug collision requiring overwrite) permanently discards the user's idea and slug. Await a success result from run and clear these fields only when j.ok is true.
  run("speckit-assess-intake", slug || null, idea, null, false);
  document.getElementById("idea").value = "";
  document.getElementById("newslug").value = "";

.github/extensions/assess-canvas/extension.mjs:280

  • list_assessments promises per-stage progress, but each returned assessment omits stages and exposes only an aggregate count/next stage. Agent callers therefore cannot determine which artifacts exist or are stale, despite the README documenting that capability. Include the stage-state map in each item.
                    assessments: state.assessments.map((a) => ({
                        slug: a.slug,
                        title: a.title,
                        completed: a.completed,
                        total: a.total,
                        nextStage: a.nextStage,
                        verdict: a.verdict,
                    })),
  • Files reviewed: 5/5 changed files
  • Comments generated: 2
  • Review effort level: Balanced

We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.

Comment thread .github/extensions/assess-canvas/assess.js Outdated
Protect loopback routes with per-instance capabilities and canonical request checks, reject intermediate symlinks, propagate stale inputs, and align UI and clarification guards with current stage state.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
Copilot AI review requested due to automatic review settings August 3, 2026 15:41

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Not ready to approve

Setup reliability, clarification races, root detection, and unbounded artifact reads need correction.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.

Review details

Suppressed comments (4)

.github/extensions/assess-canvas/extension.mjs:134

  • A clarification is re-read and selected only by its numeric index. Because the artifact can be regenerated while this full-page preview remains open, that index may now identify a different question, causing the submitted answer to rerun a stage for the wrong clarification. Send the displayed question or a content digest with the request and reject submission unless it still matches the current artifact.
    const artifact = readArtifact(PROJECT_ROOT, slug, stage.key);
    if (!artifact.ok) return { error: artifact.error };
    const clarification = extractClarifications(artifact.content)[index];
    if (!clarification) return { error: "clarification no longer exists" };

.github/extensions/assess-canvas/assess.js:98

  • readIfFile synchronously loads an unbounded repository file. scanAssessments calls this for intake and decision artifacts on every 1.5-second poll, so one oversized artifact can repeatedly block the server or exhaust the extension process's memory. Enforce a file-size limit before reading (and use a bounded prefix for title/verdict scans), with a distinct oversized-file result for previews.
function readIfFile(p) {
    try {
        const stat = lstatSync(p);
        if (stat.isSymbolicLink() || !stat.isFile()) return null;
        return readFileSync(p, "utf8");

.github/extensions/assess-canvas/assess.js:54

  • This recognizes only a .git directory, but Git worktrees and submodules use a regular .git file. When Copilot is launched from a nested directory in either case and .specify is absent, root discovery falls back to that nested directory and setup initializes the wrong location. Accept a non-symlink regular .git file as a Git-root marker too.
        if (gitRoot === null && isRealDir(join(dir, ".git"))) gitRoot = dir;

.github/extensions/assess-canvas/extension.mjs:32

  • The setup command omits --script, so the PTY-backed agent shell can stop at the interactive script-type chooser instead of completing setup. This repository requires every agent-run specify init to pass that flag (skills/speckit-init/SKILL.md:76-79,91-98); use the cross-platform py option here.
    "If `.specify/` is missing, run `specify init --here --force --integration copilot --integration-options=\"--skills\"`.",
  • Files reviewed: 5/5 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.

Address review feedback for bounded reads, worktree root detection, setup flags, and clarification races. Declare the canvas as a plugin extension component so marketplace installs include it.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
Copilot AI review requested due to automatic review settings August 3, 2026 16:51
@mnriem
mnriem marked this pull request as ready for review August 3, 2026 17:00

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Not ready to approve

Extension startup, dispatch reliability, project isolation, and filesystem race issues remain unresolved.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.

Review details

Suppressed comments (9)

.github/extensions/assess-canvas/extension.mjs:234

  • Await session.send() before returning HTTP 200. The SDK returns a promise, so the current endpoint tells the UI setup was sent even when dispatch rejects and leaves the rejection unhandled.
                session.send({ prompt: SETUP_PROMPT });

.github/extensions/assess-canvas/extension.mjs:332

  • This action reports success before the asynchronous send is accepted. Await the SDK call so dispatch failures propagate through the action instead of becoming unhandled rejections.
                session.send({ prompt: SETUP_PROMPT });

.github/extensions/assess-canvas/extension.mjs:401

  • This action returns { ok: true } without awaiting the asynchronous send. Await it so a rejected dispatch is surfaced to the caller rather than falsely reported as successful.
                session.send({ prompt: built.prompt });

.github/extensions/assess-canvas/extension.mjs:264

  • Await session.send() before returning success. Otherwise a failed stage dispatch still produces { ok: true } and an unhandled promise rejection.
                session.send({ prompt: built.prompt });

.github/extensions/assess-canvas/extension.mjs:158

  • session.send() is asynchronous, but this helper returns { ok: true } without waiting for it. A rejected send therefore becomes an unhandled rejection while both callers report success. Make clarificationRun async, await the send, and await this helper from the HTTP and canvas-action handlers.

This issue also appears in the following locations of the same file:

  • line 234
  • line 264
  • line 332
  • line 401
    session.send({ prompt });
    return {

.github/extensions/assess-canvas/extension.mjs:63

  • decide is allowed when an existing concept.md is stale. After Define is rerun, this lets the Decide skill read an obsolete concept; moreover scanAssessments() necessarily marks the newly written decision stale because a previous stage remains stale. Block Decide when a concept exists but Shape is not current, or explicitly ignore the stale concept and align the scanner/UI with that policy.
function stagePrerequisiteError(stageKey, assessment) {
    if ((stageKey === "shape" || stageKey === "decide") && !assessment?.stages?.define?.done) {
        return `${stageKey} requires a current problem.md; rerun define first`;
    }

.github/extensions/assess-canvas/assess.js:148

  • Directory presence does not prove the assess skills are usable. A disabled assess installation can leave this directory while its registry entry is disabled, and a project initialized without Copilot skills mode can have the extension files but no speckit-assess-* skills. In both cases setupRequired becomes false and every action dispatches a missing skill. Validate the registry's enabled/registered-skills state and the expected generated skills before declaring readiness.
    const assessInstalled = initialized && hasRealDirectoryChain(projectRoot, ".specify", "extensions", "assess");

.github/extensions/assess-canvas/index.html:180

  • All validation and dispatch feedback is written into this transient toast, but it is not exposed as a live region. Screen-reader users will not be notified when input is rejected or a stage succeeds/fails. Mark it as a polite status region.
<div class="toast" id="toast"></div>

plugin.json:21

  • Adding a distributable extension without changing the plugin version leaves both plugin.json and the two marketplace version fields at 0.15.0. Marketplace update flows can therefore treat this build as the already-installed release and never deliver the canvas. Bump all three plugin/marketplace versions together for this release.
  "extensions": ".github/extensions/"
  • Files reviewed: 8/8 changed files
  • Comments generated: 4
  • Review effort level: Balanced

We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.

Comment thread .github/extensions/assess-canvas/extension.mjs Outdated
Comment thread .github/extensions/assess-canvas/assess.mjs
Comment thread .github/extensions/assess-canvas/assess.js Outdated
Comment thread .github/extensions/assess-canvas/assess.js Outdated
Make extension modules portable, isolate project-root discovery, verify no-follow file descriptors, await SDK dispatch, validate assess skill readiness, and publish plugin version 0.15.1.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
Copilot AI review requested due to automatic review settings August 3, 2026 17:24

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Not ready to approve

Registry truncation and missing overwrite confirmation can cause incorrect setup state and unauthorized reruns.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.

Review details

Suppressed comments (2)

.github/extensions/assess-canvas/assess.mjs:196

  • readJsonIfFile parses only the first 64 KiB, so any valid extension registry larger than that is truncated and rejected. The registry format has no corresponding 64 KiB limit; once enough extensions/metadata are installed, this makes assessInstalled false and permanently routes the canvas back to setup. Read the complete registry through the bounded, descriptor-verified reader instead of the scan prefix.
function readJsonIfFile(p, realRoot) {
    const text = readPrefixIfFile(p, realRoot);
    if (text === null) return null;

.github/extensions/assess-canvas/extension.mjs:360

  • The agent-callable clarification action can overwrite an existing stage artifact without carrying the explicit overwrite confirmation required by run_stage. Nevertheless, clarificationRun tells the agent that the user explicitly confirmed the overwrite. Require an overwrite: true field for this action and reject calls without it; the HTTP path can continue relying on its confirmation dialog.
                    answer: { type: "string" },
                },
                required: ["slug", "stage", "index", "question", "answer"],
  • Files reviewed: 8/8 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.

Publish the Idea Assessment canvas independently as spec-kit-copilot-assess, keep the core skills plugin focused, and describe the repository as the Copilot integration hub for Spec Kit.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
Copilot AI review requested due to automatic review settings August 3, 2026 19:05

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Not ready to approve

The canvas lifecycle has a server-leak race, and input and accessibility validation need correction.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.

Review details

Suppressed comments (3)

plugins/spec-kit-copilot-assess/extensions/assess-canvas/extension.mjs:413

  • Concurrent opens for the same instanceId can both pass this check because the map is not populated until startServer() resolves. One entry then overwrites the other, so the first loopback server and polling timer are never closed; a close arriving during startup has the same leak. Store a shared startup promise before awaiting it, and make onClose await and clean that promise.
        let entry = servers.get(ctx.instanceId);
        if (!entry) {
            entry = await startServer(ctx.instanceId);
            servers.set(ctx.instanceId, entry);

plugins/spec-kit-copilot-assess/extensions/assess-canvas/assess.mjs:45

  • This accepts arbitrarily long normalized slugs. A slug longer than the filesystem's component limit passes the API validation and is sent to the skill, but creating .specify/assessments/<slug> then fails with ENAMETOOLONG; reject oversized slugs before reporting the run as sent.
    return SLUG_RE.test(slug) ? slug : "";

plugins/spec-kit-copilot-assess/extensions/assess-canvas/index.html:153

  • The symbol-only button's accessible name is “×”, which does not describe its purpose to screen-reader users. Give it meaningful text; the artifact-view code can still replace that text with “← Dashboard”.
      <button class="closex" id="closeArt" title="Close">×</button>
  • Files reviewed: 9/9 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
Copilot AI review requested due to automatic review settings August 3, 2026 19:11
@mnriem
mnriem merged commit b2ff4eb into github:main Aug 3, 2026
@mnriem
mnriem deleted the mnriem-install-assess-canvas branch August 3, 2026 19:14

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Not ready to approve

Setup-state controls and dialog accessibility need correction before approval.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.

Review details

Suppressed comments (3)

plugins/spec-kit-copilot-assess/extensions/assess-canvas/index.html:170

  • This dialog also lacks an accessible name. Give the heading an ID and reference it with aria-labelledby so assistive technology can identify the clarification dialog.
<dialog id="clarifyDialog">
  <h2>Resolve clarification</h2>

plugins/spec-kit-copilot-assess/extensions/assess-canvas/index.html:290

  • When setup is required, existing assessment cards are still rendered and this helper enables intake/research/define (and possibly downstream stages). Those controls then always fail because /api/run returns 409 in the same state. Disable all stage controls while setupRequired is true so the setup action is genuinely the first available step.
function canRunStage(stage, assessment) {
  if (stage === "intake" || stage === "research" || stage === "define") return true;

plugins/spec-kit-copilot-assess/extensions/assess-canvas/index.html:158

  • The native dialog has no accessible name; descendant headings do not automatically name a dialog. Associate it with the existing heading so screen readers announce what opened.

This issue also appears on line 169 of the same file.

<dialog id="stageDialog">
  • Files reviewed: 9/9 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants